﻿
namespace Huirui.Cavan.Presentation.Seedwork
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.Linq;
    using System.Web.Mvc;
    using Huirui.Cavan.Core.Extension;
    using Huirui.Cavan.Application.MainBoundedContext.SystemModule;
    using Huirui.Cavan.Core.Message;
    using System.Threading;
    using System.Web.Security;
    using Spring.Context;
    using Spring.Context.Support;
    using Huirui.Cavan.Domain.MainBoundedContext.SystemModule;
    using Huirui.Cavan.Domain.MainBoundedContext.SearchModule;

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Method, AllowMultiple = true)]
    public class AccessFilterAttribute : AuthorizeAttribute
    {
        private bool _passed = false;
        #region IAuthorizationFilter Members
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var controller = filterContext.Controller as IWebController<IWebModel>;
            var actionName = filterContext.RouteData.Values["action"].ToString();
            object[] attrs = filterContext.ActionDescriptor.GetCustomAttributes(typeof(ActionPermissionAttribute), true);
            ActionPermissionAttribute actionUsedDeniedAttribute = new ActionPermissionAttribute();
            if (attrs != null && attrs.Length > 0)
            {
                actionUsedDeniedAttribute = (ActionPermissionAttribute)attrs[0];
            }

            controller.Model.MasterModel.ControllerName = controller.ControllerName;
            controller.Model.MasterModel.CurrentAction = actionName;
            var model = controller.Model.MasterModel.CurrentUserModel;

            if (controller.Is())
            {
                try
                {
                    _passed = true;
                    if (controller.UseDenied)//控制器是否需要验证
                    {
                        if (!Thread.CurrentPrincipal.Identity.IsAuthenticated)
                        {
                            filterContext.Result = new HttpUnauthorizedResult();
                            _passed = false;
                        }
                        else
                        {
                            if (actionUsedDeniedAttribute.IsUsedDenied)
                            {
                                if (SecurityAppService.UserAccount.Role.IsUseDenied)//用户角色是否需要验证
                                {
                                    IApplicationContext SpringContext = ContextRegistry.GetContext();
                                    ISysControllerAppService sysControllerAppService = SpringContext.GetObject("SysControllerAppService") as ISysControllerAppService;
                                    ISysActionAppService sysActionAppService = SpringContext.GetObject("SysActionAppService") as ISysActionAppService;
                                    SysController sysController = sysControllerAppService.GetSingleBySearch(new SysControllerSearch() {  Name = controller.ControllerName});
                                    SysAction sysAction = sysActionAppService.GetSingleBySearch(new SysActionSearch() { ControllerID = sysController.Id, Name = actionUsedDeniedAttribute.Name});
                                    if (SecurityAppService.GrantedActions.Any(ga => ga.Id == sysAction.Id))
                                    {
                                        _passed = true;
                                    }
                                    else
                                    {
                                        _passed = false;
                                    }
                                }
                                else
                                {
                                    _passed = true;
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    this.Log().Fatal("验证失败", ex);
                }
            }

            if (!_passed)
            {
                controller.Model.Messages.Clear();
                controller.Model.Messages.AddError(controller, "NoAccess", "没有权限 {0} {1} {2}", SecurityAppService.UserAccount.Name, controller.ControllerName, actionName);

                DenyAccess(filterContext);
            }
            base.OnAuthorization(filterContext);
        }

        protected override bool AuthorizeCore(System.Web.HttpContextBase httpContext)
        {
            return _passed;
        }

        protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.HttpContext.Response.Clear();
                filterContext.Result = new JsonResult
                {
                    Data = new
                    {
                        IsSuccess = false,
                        Message = "未授权"
                    },
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet
                };
                return;
            }
            base.HandleUnauthorizedRequest(filterContext);
        }
        #endregion

        #region protected DenyAccess transfer
        protected virtual void DenyAccess(AuthorizationContext filterContext)
        {
            var controllerName = (string)filterContext.RouteData.Values["controller"];
            var action = (string)filterContext.RouteData.Values["action"];
            var controller = filterContext.Controller as IWebController<IWebModel>;

            var messages = controller.Is()
                               ? controller.Model.Messages
                               : new List<AppMessage>();
            // Model
            var model = new ExceptionModel();

            model.MasterModel.ControllerName = controllerName;
            model.MasterModel.CurrentAction = action;
            model.Messages = messages;

            // View result
            if (controller.Is())
            {
                var result = new ViewResult
                {
                    ViewData = new ViewDataDictionary<IExceptionModel>(model),
                    ViewName = @"~\Views\Error\NoAccess.cshtml"
                };
                filterContext.Result = result;
            }
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 403; // not authorized
        }
        #endregion protected DenyAccess transfer
    }
}